import json
import random
import string
import traceback
import logging
from  datetime import datetime

from io import BytesIO
from captcha.image import ImageCaptcha
from sqlalchemy import or_
from flask import Blueprint, make_response,Response
from flask_restful import Api,Resource,reqparse,marshal
from werkzeug.security import generate_password_hash,check_password_hash

from celery_tasks.tasks import phone_code
from common.models import db,rds
from common.models.users import UserModels
from common.utils.jwt_utils import _generate_token, refresh_token
# from common.utils.captcha import Captcha
from common.utils.my_output_json import custom_output_json
from common.model_fields.user_fields import user_fields

user_bp = Blueprint('user_bp', __name__, url_prefix='/user')
api = Api(user_bp)

# 使用representation把所有返回的数据进行统一化
@api.representation('application/json')
def output_json(data, code, headers=None):
    resp = custom_output_json(data, code, headers)
    return resp

class GenerateImgCode(Resource):
    """生成图片验证码"""
    def get(self):
        try:
            parser = reqparse.RequestParser()
            parser.add_argument('uuid')
            args = parser.parse_args()
            uuid = args.get('uuid')

            imgs = ''.join(random.sample(string.ascii_letters+string.digits, 5))
            print("imgs--->", imgs)
            captcha = ImageCaptcha()

            img = captcha.generate(imgs)
            # img = captcha.generate_image(imgs)

            # 保存验证码到redis
            rds.setex(uuid, 60 * 5, imgs)
            # print('img---->', img)
            # resp = make_response(img)
            # resp.content_type = 'image/png'
            return Response(img)
        except:
            error = traceback.format_exc()
            logging.error('图片验证码 错误{}'.format(error))
            return 'fail'

class SendMessageCode(Resource):
    """
    发送短信验证码
    1、生成验证码
    2、保存验证码到redis
    3、调用接口发送验证码
    """
    def get(self):
        parser = reqparse.RequestParser()
        parser.add_argument('phone')
        args = parser.parse_args()
        phone = args.get('phone')

        # 判断此手机号是否短时间内重复发送
        if rds.get(phone):
            return {'message': '短信已发送，请不要重复发送短信'}, 409

        # 生成验证码
        code = str(random.randint(100000, 999999))
        # 发送验证码
        try:
            rds.setex(phone, 60, code)
            # 发送短信
            result = json.loads(phone_code(phone, code))
            if result.get('statusCode') == "112310" or result.get('statusCode') == "000000":
                return {'message': '发送验证码成功', 'code': 200}
            else:
                return {'message': '发送验证码失败', 'code': 400}
        except:
            error = traceback.format_exc()
            logging.error('mes error:{}'.format(error))
            return {'message': error, 'code': 500}

class UserRegister(Resource):
    """
       注册账号
       1、获取信息（账号、密码（两个）、手机号、验证码
       2、数据校验（账号长度、密码长度、不能为空），账号是否唯一、手机号是否唯一、验证码是否正确
       3、添加账号
    """

    def _check_base_params(self, account, password, phone, confirm_password, code):
        """
        验证参数
        """
        if not all([account, password, phone, confirm_password, code]):
            return {'message': '参数不完整错误', 'code': 405}

        # 账号长度验证
        if len(account) > 20:
            return {'message': '账号长度不符合规则', 'code': 405}

        # 密码长度
        if len(password) > 20:
            return {'message': '密码太长', 'code': 405}

        if password != confirm_password:
            return {'message': '两次密码不一致', 'code': 405}

        # 从redis中取出短信验证码
        real_msg_code = rds.get(phone)
        # 判断是否存在 不存在
        if not real_msg_code:
            return {'code': 405, 'message': '验证码已过期'}
        real_msg_code = real_msg_code.decode()
        # 进行验证是否一致
        if real_msg_code != code:
            return {'code': 405, 'message': '验证码错误'}

        # 验证手机号是否已使用
        number = UserModels.query.filter_by(phone=phone).count()
        if number >= 1:
            return {'code': 405, 'message': '手机号已绑定'}

        # 验证用户是否已经注册
        user = UserModels.query.filter_by(account=account).first()
        if user:
            return {'code': 405, 'message': '账号已存在'}
        return {'code': 200}

    def post(self):
        try:
            # 获取参数
            parser = reqparse.RequestParser()
            args_list = ['username', 'password', 'phone', 'code', 'password2']
            for args in args_list:
                parser.add_argument(args)
            args = parser.parse_args()
            account = args.get('username')
            password = args.get('password')
            confirm_password = args.get('password2')
            # 手机号
            phone = args.get('phone')
            # 手机验证码
            code = args.get('code')

            # 验证参数
            check_result = self._check_base_params(account, password, phone, confirm_password, code)
            print('11111111111', check_result)
            if check_result['code'] != 200:
                return check_result

            # 通过验证，注册用户
            user = UserModels(account=account, password=generate_password_hash(password), phone=phone)
            user.last_login_time = datetime.now()
            db.session.add(user)
            db.session.commit()
            print("user---->", user)
            return marshal(user, user_fields)
        except:
            error = traceback.format_exc()
            logging.error('register_user error:{}'.format(error))
            return {'error': error, 'code': 500}


class LoginResource(Resource):
    def post(self):
        pars = reqparse.RequestParser()
        pars.add_argument('account')
        pars.add_argument('password')
        pars.add_argument('uuid')
        pars.add_argument('img_code')
        args = pars.parse_args()
        uuid = args.get('uuid')
        img_code = args.get('img_code')
        account = args.get('account')
        password = args.get('password')
        print(">>>>>~~~~", account, password,uuid, img_code)
        # 校验图片验证码
        real_code = rds.get(uuid)
        if not real_code:
            return {'code': 407, 'message': '验证码过期'}
        real_code = real_code.decode()
        real_code = real_code.lower()
        code = img_code.lower()
        if real_code != code:
            return {'code': 406, 'message': '验证码错误'}

        user = UserModels.query.filter(or_(UserModels.account == account, UserModels.phone == account)).first()
        print('当前登录的用户信息>>>',user)
        if not user:
            return {'msg': '账号或手机号错误', 'code':400}
        if not check_password_hash(user.password,password):
            return {'code': 400, 'msg': '密码错误'}
        user_id = user.uid
        # 生成token，返回token
        # 现在进行的是web开发
        token, refresh_token = _generate_token({'account': account, 'user_id': user_id,
                                                'is_superuser': user.is_superuser})
        print('登陆的token', token)
        data = {
            'message': 'login success',
            'data': {'code': 200, 'token': token, 'refresh': refresh_token,
                     'account': account, 'uid': user_id,}
        }
        return data


class ChangePassWordRewsource(Resource):
    def put(self):
        """修改密码"""
        parser = reqparse.RequestParser()
        args_list = [ 'pwd', 'phone', 'sms_code', 'confirm_pwd']
        for args in args_list:
            parser.add_argument(args)
        args = parser.parse_args()
        password = args.get('pwd')
        confirm_password = args.get('confirm_pwd')
        # 手机号
        phone = args.get('phone')
        # 手机验证码
        code = args.get('sms_code')
        # 密码长度
        if len(password) > 20:
            return {'message': '密码太长', 'code': 405}

        if password != confirm_password:
            return {'message': '两次密码不一致', 'code': 405}
        # 从redis中取出短信验证码
        real_msg_code = rds.get(phone)
        # 判断是否存在 不存在
        if not real_msg_code:
            return {'code': 405, 'message': '验证码已过期'}
        real_msg_code = real_msg_code.decode()
        print("redis_code.....", real_msg_code)
        print('code----->', code)
        # 进行验证是否一致
        if real_msg_code != code:
            return {'code': 405, 'message': '验证码错误'}
        # 对密码加密
        hash_pwd = generate_password_hash(password)
        # 修改密码
        try:
            UserModels.query.filter_by(mobile=phone).update({'password':hash_pwd})
            db.session.commit()
            return {'message':'修改密码成功', "code":200}
        except Exception as e:
            return {'message':'修改密码失败', 'code':500}


class UserInfoResource(Resource):
    def get(self):
        """获取用户信息"""
        parse = reqparse.RequestParser()
        parse.add_argument('uid')
        args = parse.parse_args()
        user = UserModels.query.filter_by(uid=args.get('uid')).first()
        data = marshal(user, user_fields)
        return {'message':"获取用户信息成功", "data":data,"code":200}


api.add_resource(UserRegister, '/register_user')
api.add_resource(SendMessageCode,'/phone_code')
api.add_resource(GenerateImgCode,'/img_code')
api.add_resource(LoginResource,'/login')
api.add_resource(ChangePassWordRewsource, '/change_pwd')
api.add_resource(UserInfoResource,'/get_user')
